#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <wiringPi.h>
#include <sys/time.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>
#include <MQTTClient.h>
#include <jansson.h>

/* 传感器相关定义 */
typedef struct {
    float humidity;
    float temp_celsius;
} DHT11_Data;

#define TRIG_PIN 4     // 超声波Trig引脚
#define ECHO_PIN 5     // 超声波Echo引脚
#define DHT_PIN 0      // 温湿度传感器引脚
#define LED_PIN 1      // LED控制引脚
#define BUZZER_PIN 3   // 蜂鸣器控制引脚
#define DISTANCE_THRESHOLD 50.0 // 报警距离阈值（单位：厘米）

/* MQTT平台参数 */
#define NEWLAND_SERVER    "tcp://mqtt.nlecloud.com:1883"
#define PRODUCT_ID        "1169974"
#define DEVICE_NAME       "qwerttyuiop"
#define DEVICE_SECRET     "52d1744ed7334441b1091f48fd28ebbb"
#define DATA_TOPIC    "/sys/" PRODUCT_ID "/" DEVICE_NAME "/sensor/datas"
#define CONTROL_TOPIC "/sys/" PRODUCT_ID "/" DEVICE_NAME "/control"
#define QOS         1
#define KEEP_ALIVE  60

/* 全局变量 */
bool tempAlarm = false;
unsigned long lastTempCheck = 0;
float current_distance = 0.0;
MQTTClient client;
unsigned int msg_id = 0;
bool cloud_led_ctrl = false;    // 云端LED控制状态
bool cloud_buzzer_ctrl = false; // 云端蜂鸣器控制状态
bool object_near = false;       // 物体靠近状态标志

/* DHT11读取函数（带超时保护） */
bool readDHT11(DHT11_Data *data) {
    uint8_t bits[5] = {0};
    uint8_t cnt = 7;
    uint8_t idx = 0;

    pinMode(DHT_PIN, OUTPUT);
    digitalWrite(DHT_PIN, LOW);
    delay(18);
    digitalWrite(DHT_PIN, HIGH);
    delayMicroseconds(40);
    pinMode(DHT_PIN, INPUT);

    // 等待DHT11响应（超时1ms）
    unsigned long timeout = micros() + 1000;
    while (digitalRead(DHT_PIN) == LOW) {
        if (micros() > timeout) return false;
    }

    timeout = micros() + 1000;
    while (digitalRead(DHT_PIN) == HIGH) {
        if (micros() > timeout) return false;
    }

    // 读取数据位（每个位带超时检测）
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 8; j++) {
            timeout = micros() + 100;
            while (digitalRead(DHT_PIN) == LOW) {
                if (micros() > timeout) return false;
            }

            unsigned long t = micros();
            timeout = micros() + 100;
            while (digitalRead(DHT_PIN) == HIGH) {
                if (micros() > timeout) return false;
            }

            if ((micros() - t) > 40) bits[i] |= (1 << cnt);
            if (cnt == 0) {
                cnt = 7;
                idx++;
            } else cnt--;
        }
    }

    if (bits[4] != (bits[0] + bits[1] + bits[2] + bits[3])) return false;

    data->humidity = bits[0];
    data->temp_celsius = bits[2];
    return true;
}

/* 超声波测距（带超时保护） */
float getDistance() {
    digitalWrite(TRIG_PIN, LOW);
    delayMicroseconds(2);
    digitalWrite(TRIG_PIN, HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIG_PIN, LOW);

    struct timeval start, stop;
    unsigned long timeout = 50000; // 50ms超时

    // 等待回波信号（带超时）
    unsigned long start_wait = micros();
    while (!digitalRead(ECHO_PIN)) {
        if (micros() - start_wait > timeout) return -1;
    }
    gettimeofday(&start, NULL);

    start_wait = micros();
    while (digitalRead(ECHO_PIN)) {
        if (micros() - start_wait > timeout) return -1;
    }
    gettimeofday(&stop, NULL);

    long travelTime = (stop.tv_sec - start.tv_sec) * 1000000 + 
                     (stop.tv_usec - start.tv_usec);
    return (travelTime * 0.0343) / 2;
}

/* MQTT消息回调 */
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message) {
    char *payload = (char*)message->payload;
    printf("收到控制指令: %.*s\n", message->payloadlen, payload);
    
    // 解析JSON指令
    json_t *root = json_loads(payload, 0, NULL);
    if(root) {
        json_t *led = json_object_get(root, "led");
        json_t *buzzer = json_object_get(root, "buzzer");
        
        if(json_is_boolean(led)) 
            cloud_led_ctrl = json_boolean_value(led);
        
        if(json_is_boolean(buzzer)) 
            cloud_buzzer_ctrl = json_boolean_value(buzzer);
        
        json_decref(root);
    }

    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}

/* MQTT初始化 */
int mqtt_init() {
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    int rc;

    if (MQTTClient_create(&client, NEWLAND_SERVER, DEVICE_NAME,
        MQTTCLIENT_PERSISTENCE_NONE, NULL) != MQTTCLIENT_SUCCESS) {
        fprintf(stderr, "MQTT客户端创建失败\n");
        return -1;
    }

    MQTTClient_setCallbacks(client, NULL, NULL, msgarrvd, NULL);

    conn_opts.keepAliveInterval = KEEP_ALIVE;
    conn_opts.cleansession = 1;
    conn_opts.username = PRODUCT_ID;
    conn_opts.password = DEVICE_SECRET;
    conn_opts.MQTTVersion = MQTTVERSION_3_1_1;

    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) {
        fprintf(stderr, "连接失败: %s\n", MQTTClient_strerror(rc));
        return -1;
    }

    if (MQTTClient_subscribe(client, CONTROL_TOPIC, QOS) != MQTTCLIENT_SUCCESS) {
        fprintf(stderr, "订阅控制主题失败\n");
        return -1;
    }

    return 0;
}

/* 数据上报 */
void mqtt_publish(DHT11_Data data, float distance) {
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    char payload[256];
    time_t now = time(NULL);

    snprintf(payload, sizeof(payload),
        "{"
        "\"msgId\":%u,"
        "\"datatype\":1,"
        "\"timestamp\":%ld,"
        "\"datas\":{"
            "\"m_temperature\":%.1f,"
            "\"m_humidity\":%.1f,"
            "\"m_distance\":%.2f"
        "}"
        "}",
        ++msg_id, now, data.temp_celsius, data.humidity, distance);

    pubmsg.payload = payload;
    pubmsg.payloadlen = (int)strlen(payload);
    pubmsg.qos = QOS;
    pubmsg.retained = 0;

    MQTTClient_deliveryToken token;
    if (MQTTClient_publishMessage(client, DATA_TOPIC, &pubmsg, &token) != MQTTCLIENT_SUCCESS) {
        fprintf(stderr, "数据上报失败\n");
    } else {
        printf("已上报: 温度=%.1fC 湿度=%.1f%% 距离=%.2fcm\n",
              data.temp_celsius, data.humidity, distance);
    }
}

int main() {
    if(wiringPiSetup() == -1) {
        fprintf(stderr, "wiringPi初始化失败\n");
        return EXIT_FAILURE;
    }

    /* 硬件初始化 */
    pinMode(TRIG_PIN, OUTPUT);
    digitalWrite(TRIG_PIN, LOW);
    pinMode(ECHO_PIN, INPUT);
    pinMode(LED_PIN, OUTPUT);
    pinMode(BUZZER_PIN, OUTPUT);
    digitalWrite(LED_PIN, LOW);
    digitalWrite(BUZZER_PIN, LOW);

    /* MQTT连接 */
    if (mqtt_init() != 0) {
        fprintf(stderr, "MQTT初始化失败\n");
        return EXIT_FAILURE;
    }

    DHT11_Data dhtData;
    unsigned long lastDistanceCheck = 0;
    unsigned long lastMQTTPublish = 0;

    while (1) {
        unsigned long currentMillis = millis();

        /* 每2秒读取温湿度 */
        if (currentMillis - lastTempCheck > 2000) {
            if (readDHT11(&dhtData)) {
                tempAlarm = dhtData.temp_celsius > 27.0;
                printf("本地传感器: %.1fC | %.1f%%\n", 
                      dhtData.temp_celsius, dhtData.humidity);
            }
            lastTempCheck = currentMillis;
        }

        /* 每200ms更新距离 */
        if (currentMillis - lastDistanceCheck > 200) {
            float distance = getDistance();
            if (distance >= 0) {
                current_distance = distance;
                object_near = (distance < DISTANCE_THRESHOLD);
            }
            lastDistanceCheck = currentMillis;
        }

        /* 报警优先级处理 */
        if (tempAlarm) { // 温度报警最高优先级
            digitalWrite(BUZZER_PIN, HIGH);
            digitalWrite(LED_PIN, (currentMillis % 1000 < 500) ? HIGH : LOW);
        } 
        else if (object_near) { // 超声波报警次优先级
            digitalWrite(LED_PIN, HIGH);
            digitalWrite(BUZZER_PIN, HIGH);
        } 
        else { // 正常模式响应云端控制
            digitalWrite(LED_PIN, cloud_led_ctrl);
            digitalWrite(BUZZER_PIN, cloud_buzzer_ctrl);
        }

        /* 每30秒上报数据 */
        if (currentMillis - lastMQTTPublish > 30000) {
            mqtt_publish(dhtData, current_distance);
            lastMQTTPublish = currentMillis;
        }

        /* 非阻塞延迟（允许MQTT处理消息） */
        MQTTClient_yield();
        delay(10);
    }

    MQTTClient_disconnect(client, 10000);
    MQTTClient_destroy(&client);
    return 0;
}